import { ComponentFixture, fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing';
import { ChangeDetectionStrategy, Component, TemplateRef, ViewChild } from '@angular/core';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { ModalModule } from './modal.module';
import { ModalService } from './modal.service';
import { ModalTypeEnum } from './interface';

@Component({
  template: `
    <button (click)="open()">Service</button>
    <ng-template #contentTpl>
      <div>This is modal content1...</div>
    </ng-template>
    <ng-template #contentTpl2>
      <div>This is modal content2...</div>
    </ng-template>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
class TestModalComponent {
  constructor(private modalService: ModalService) {}

  @ViewChild('contentTpl', { static: false }) contentTpl: TemplateRef<any>;
  @ViewChild('contentTpl2', { static: false }) contentTpl2: TemplateRef<any>;

  type = ModalTypeEnum.MODAL;
  isUpdate = false;
  ok() {}
  cancel() {}

  update() {
    this.modalService.update('myModal', {
      lvWidth: 600,
      lvHeader: 'Update',
      lvContent: this.contentTpl2,
      lvKeyboardEscape: true,
    });
  }

  open() {
    this.modalService.create({
      lvModalKey: 'myModal',
      lvType: this.type,
      lvHeader: 'Title',
      lvContent: this.contentTpl,
      lvOk: this.ok,
      lvCancel: this.cancel,
      lvFooter: this.isUpdate
        ? [
            {
              id: 'ok',
              label: 'Ok',
              type: 'primary',
              onClick: () => {
                this.update();
              },
            },
          ]
        : [],
    });
  }
}

describe('ModalComponent', () => {
  beforeEach(
    waitForAsync(() => {
      TestBed.configureTestingModule({
        declarations: [TestModalComponent],
        imports: [ModalModule, NoopAnimationsModule],
        teardown: { destroyAfterEach: true },
      }).compileComponents();
    })
  );

  describe('render', () => {
    let component: TestModalComponent;
    let fixture: ComponentFixture<TestModalComponent>;
    const renderComp = fakeAsync(para => {
      for (const [key, value] of Object.entries(para)) {
        component[key] = value;
      }
      const button = fixture.nativeElement.querySelector('button');
      button.dispatchEvent(new Event('click'));
      tick(1500);
      fixture.detectChanges();
      expect(document.activeElement).toMatchSnapshot();
    });

    beforeEach(() => {
      fixture = TestBed.createComponent(TestModalComponent);
      component = fixture.componentInstance;
    });

    it('with lvType modal', () => {
      renderComp({ type: ModalTypeEnum.MODAL });
    });

    it('with lvType drawer', () => {
      renderComp({ type: ModalTypeEnum.DRAWER });
    });
  });

  describe('work', () => {
    let component: TestModalComponent;
    let fixture: ComponentFixture<TestModalComponent>;
    let button;

    beforeEach(fakeAsync(() => {
      fixture = TestBed.createComponent(TestModalComponent);
      component = fixture.componentInstance;
      fixture.autoDetectChanges();
      button = fixture.nativeElement.querySelector('button');
    }));

    // 点击展开modal，能正常点击(确认，取消，右上角)关闭
    it('should work correctly', fakeAsync(() => {
      ['#lvModalOkButton', '#lvModalCancelButton', '#lvModalCloseButton'].forEach(buttonId => {
        button.dispatchEvent(new Event('click'));
        tick(1500);
        fixture.detectChanges();
        let modalBody = document.querySelector('.lv-modal-body');
        expect(modalBody).not.toBeNull();
        const closeButton = document.querySelector(buttonId);
        closeButton.dispatchEvent(new Event('click'));
        tick(1500);
        fixture.detectChanges();
        modalBody = document.querySelector('.lv-modal-body');
        expect(modalBody).toBeNull();
      });
    }));

    // 确认取消异步事件，可阻止modal关闭
    it('should work when async', fakeAsync(() => {
      component.ok = () => false;
      component.cancel = () => false;
      button.dispatchEvent(new Event('click'));
      tick(1500);
      fixture.detectChanges();
      let modalBody = document.querySelector('.lv-modal-body');
      expect(modalBody).not.toBeNull();

      ['#lvModalOkButton', '#lvModalCancelButton'].forEach(buttonId => {
        const closeButton = document.querySelector(buttonId);
        closeButton.dispatchEvent(new Event('click'));
        tick(1500);
        fixture.detectChanges();
        modalBody = document.querySelector('.lv-modal-body');
        expect(modalBody).not.toBeNull();
      });
    }));

    // 弹窗更新
    it('should work when update', fakeAsync(() => {
      component.isUpdate = true;
      button.dispatchEvent(new Event('click'));
      tick(1500);
      fixture.detectChanges();

      let title = document.querySelector('.lv-modal-title');
      let content = document.querySelector('.lv-modal-body');
      expect(title.textContent).toContain('Title');
      expect(content.textContent).toContain('content1');
      const okButton = document.querySelector('#ct_ok');
      okButton.dispatchEvent(new Event('click'));
      tick(1500);
      fixture.detectChanges();
      title = document.querySelector('.lv-modal-title');
      content = document.querySelector('.lv-modal-body');
      expect(title.textContent).toContain('Update');
      expect(content.textContent).toContain('content2');
    }));
  });
});
